import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:path/path.dart';
part 'version.dart';

/// C/CPP 工具使用C/CPP写的工具
///
/// 1. Dart只能调用C函数,NativeType 是 Dart 中定义的抽象类，用于表示一种 Native 类型，它无法在 Dart 中进行构造，只能通过 FFI 接口返回
///
/// 2. Dart调用C函数:
/// ``` dart
/// ///对应C语言函数声明：int32_t native_add(int32_t x, int32_t y),函数的参数和返回值都属性 NativeType
/// typedef Native_add = Int32 Function(Int32 x, Int32 y);
///
/// ///Dart使用的函数
/// typedef FFI_add = int Function(int x, int y);
///
/// ///lookupFunction() 其实就是 lookup() 和 asFunction() 的封装，简化代码。
/// ```
/// 3. Dart 中，只有全局函数才能给被 C 调用,我们可以通过 Pointer.fromFunction() 函数将 Dart Function 转为 C 的函数指针
/// 4. 字符串使用ffi 库把 C 的字符串映射到 Dart 中使用：String greeting = result.cast<Utf8>().toDartString();
/// Pointer<Int8> nativeValue = value.toNativeUtf8().cast<Int8>();
/// freeFunc(nativeValue); //或者调用 calloc.free(nativeValue);
///
/// 5. final Pointer<Person> pAlice = nativeApi.lookup<Person>("g_alice");
/// final Person alice = pAlice.ref; //获取指针所指向的对象
///
/// 6. 强制转换Pointer<Uint> uintPointer = Pointer.cast(voidPointer);
///
class CppTools {
  static final CppTools _instance = CppTools._internal();
  CppTools._internal();
  static CppTools getInstance() => _instance;
  late final DynamicLibrary _cppHandler;

  ///加载当前进程的动态链接库,可能有符号相同被覆盖的情况

  /// 加载包含当前 Dart 程序的可执行文件的动态链接库
  ///_cppHandler = DynamicLibrary.executable();
  void init({String? path}) {
    try {
      _cppHandler = DynamicLibrary.open(join(path ?? '', 'cpp_tools.dll'));
    } catch (e) {
      _cppHandler = DynamicLibrary.process();
    }
  }

  ///获取库版本号
  String getVersion() => _cppHandler
      .lookup<Pointer<Int8>>('version')
      .value
      .cast<Utf8>()
      .toDartString();

  /// dart调用C函数测试用例
  ///
  /// 传递结构体过去,将size大小以及字符串加到结构体上后返回
  /// 后续还要测试赋值数据类型,队列,表,数组等
  ///
  /// [test] : 指针结构体
  ///
  /// [func] :  dart回调函数,由C调用
  ///
  /// [size] :  基本类型
  ///
  /// [test] :  常用的字符串转换
  Pointer<MyStruct> dartToCTest(Pointer<MyStruct> test,
          Pointer<NativeFunction<TestCB>> func, int size, Pointer<Int8> str) =>
      _cppHandler
          .lookupFunction<
              Pointer<MyStruct> Function(Pointer<MyStruct>,
                  Pointer<NativeFunction<TestCB>>, Int32, Pointer<Int8>),
              Pointer<MyStruct> Function(
                  Pointer<MyStruct>,
                  Pointer<NativeFunction<TestCB>>,
                  int,
                  Pointer<Int8>)>('DartToCTest')
          .call(test, func, size, str);
}
